package com.flow.framework.cipher.algorithm;

import com.flow.framework.cipher.algorithm.version.BcryptVersion;
import com.flow.framework.cipher.algorithm.version.RsaVersion;
import com.flow.framework.cipher.algorithm.version.Sm4Version;
import com.flow.framework.cipher.pojo.bo.CipherKeyPairBo;
import com.flow.framework.common.error.SystemErrorCode;
import com.flow.framework.common.exception.CheckedException;
import lombok.extern.slf4j.Slf4j;

import java.io.InputStream;

/**
 * 加密或摘要工具类
 *
 * @author luoguopiao
 * @version 0.0.1
 * @date 2022/1/16
 */
@Slf4j
public class CipherUtil {

    /**
     * 初始化国密4的秘钥
     *
     * @param version version
     * @return key
     */
    public static String generateSm4Key(Sm4Version version) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Sm4.generateKey(version);
    }

    /**
     * 国密4加密
     *
     * @param version    version
     * @param content    content
     * @param encryptKey encryptKey
     * @return
     */
    public static String encryptBySm4(Sm4Version version, String content, String encryptKey) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Sm4.encrypt(version, content, encryptKey);
    }

    /**
     * 国密4加密
     *
     * @param version      version
     * @param contentBytes contentBytes
     * @param encryptKey   encryptKey
     * @return
     */
    public static byte[] encryptBySm4(Sm4Version version, byte[] contentBytes, String encryptKey) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Sm4.encrypt(version, contentBytes, encryptKey);
    }

    /**
     * 国密4解密
     *
     * @param version    version
     * @param content    content
     * @param decryptKey decryptKey
     * @return
     */
    public static String decryptBySm4(Sm4Version version, String content, String decryptKey) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Sm4.decrypt(version, content, decryptKey);
    }

    /**
     * 国密4解密
     *
     * @param version      version
     * @param contentBytes contentBytes
     * @param decryptKey   decryptKey
     * @return
     */
    public static byte[] decryptBySm4(Sm4Version version, byte[] contentBytes, String decryptKey) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Sm4.decrypt(version, contentBytes, decryptKey);
    }

    /**
     * 初始化RSA秘钥对
     *
     * @param version version
     * @return key
     */
    public static CipherKeyPairBo generateRsaKey(RsaVersion version) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Rsa.generateKey(version);
    }

    /**
     * RSA加密
     *
     * @param version      version
     * @param content      content
     * @param publicKeyStr publicKeyStr
     * @return
     */
    public static String encryptByRsa(RsaVersion version, String content, String publicKeyStr) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Rsa.encrypt(version, content, publicKeyStr);
    }

    /**
     * RSA加密
     *
     * @param version      version
     * @param contentBytes contentBytes
     * @param publicKeyStr publicKeyStr
     * @return
     */
    public static byte[] encryptByRsa(RsaVersion version, byte[] contentBytes, String publicKeyStr) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Rsa.encrypt(version, contentBytes, publicKeyStr);
    }

    /**
     * RSA解密
     *
     * @param version       version
     * @param content       content
     * @param privateKeyStr privateKeyStr
     * @return
     */
    public static String decryptByRsa(RsaVersion version, String content, String privateKeyStr) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Rsa.decrypt(version, content, privateKeyStr);
    }

    /**
     * RSA解密
     *
     * @param version       version
     * @param contentBytes  contentBytes
     * @param privateKeyStr privateKeyStr
     * @return
     */
    public static byte[] decryptByRsa(RsaVersion version, byte[] contentBytes, String privateKeyStr) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Rsa.decrypt(version, contentBytes, privateKeyStr);
    }

    /**
     * RSA签名
     *
     * @param version    version
     * @param content    content
     * @param privateKey privateKey
     * @return
     */
    public static String signByRsa(RsaVersion version, String content, String privateKey) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Rsa.sign(version, content, privateKey);
    }

    /**
     * RSA签名
     *
     * @param version     version
     * @param inputStream inputStream
     * @param privateKey  privateKey
     * @return
     */
    public static String signByRsa(RsaVersion version, InputStream inputStream, String privateKey) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Rsa.sign(version, inputStream, privateKey);
    }

    /**
     * RSA使用公钥对私钥的签名数据进行验证
     *
     * @param version   version
     * @param content   content
     * @param publicKey publicKey
     * @param sign      私钥加签结果
     * @return
     */
    public static boolean verifySignByRsa(RsaVersion version, String content, String publicKey, String sign) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Rsa.verify(version, content, publicKey, sign);
    }

    /**
     * RSA使用公钥对私钥的签名数据进行验证
     *
     * @param version     version
     * @param inputStream inputStream
     * @param publicKey   publicKey
     * @param sign        私钥加签结果
     * @return
     */
    public static boolean verifySignByRsa(RsaVersion version, InputStream inputStream, String publicKey, String sign) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Rsa.verify(version, inputStream, publicKey, sign);
    }

    /**
     * Bcrypt加密
     *
     * @param version version
     * @param content content
     * @return
     */
    @SuppressWarnings("SpellCheckingInspection")
    public static String encryptByBcrypt(BcryptVersion version, String content) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Bcrypt.encrypt(version, content);
    }

    /**
     * 使用Bcrypt校验content加密后是否与传入的encodedContent一致
     *
     * @param version        version
     * @param content        content
     * @param encodedContent encodedContent
     * @return
     */
    @SuppressWarnings("SpellCheckingInspection")
    public static boolean verifyByBcrypt(BcryptVersion version, String content, String encodedContent) {
        if (null == version) {
            log.error("version can't be null.");
            throw new CheckedException(SystemErrorCode.PARAMS_ERROR);
        }
        return Bcrypt.verify(version, content, encodedContent);
    }
}